#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>

#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogMudule;
class Socket;

const int gdefaultsocket = -1;
const int gbacklog = 8;
const int gsize = 102400;

using SockPtr = std::shared_ptr<Socket>;

class Socket
{
public:
    virtual ~Socket() = default;
    virtual void SocketOrDie() = 0;
    virtual void SetSocketOpt() = 0;
    virtual bool BindOrDie(uint16_t port) = 0;
    virtual bool ListenOrDie() = 0;
    virtual SockPtr Accepter(InetAddr *client) = 0;
    virtual void Close() = 0;
    virtual int Recv(std::string *out) = 0;
    virtual int Send(const std::string &in) = 0;
    virtual int Fd() = 0;
    // 提供一个创建listensockfd的固定讨论
    void BuildTcpSocketMethod(int port)
    {
        SocketOrDie();
        SetSocketOpt();
        BindOrDie(port);
        ListenOrDie();
    }
};

class TcpSocket : public Socket
{

public:
    TcpSocket(int socketfd = gdefaultsocket)
        : _socketfd(socketfd)
    {
    }

    // 获得socket
    virtual void SocketOrDie()
    {
        _socketfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_socketfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket err...";
            return;
        }

        LOG(LogLevel::DEBUG) << "socket :" << _socketfd;
    }

    // 保证我们的服务器，异常断开之后，可以立即重启，不会有bind问题
    virtual void SetSocketOpt()
    {
        int opt = 1;
        int n = ::setsockopt(_socketfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        (void)n;
    }

    // 绑定
    virtual bool BindOrDie(uint16_t port)
    {
        InetAddr _addr(port);
        int n = ::bind(_socketfd, _addr.GetAddr(), _addr.Addr_size());
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "bind err...";
            return false;
        }

        LOG(LogLevel::DEBUG) << "bind succeed..." << _socketfd;
        return true;
    }

    // 监听
    virtual bool ListenOrDie()
    {
        int n = ::listen(_socketfd, gbacklog);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "listen err...";
            return false;
        }

        LOG(LogLevel::DEBUG) << "listen succeed...";
        return true;
    }

    // 重新获取套接字
    virtual SockPtr Accepter(InetAddr *client)
    {
        struct sockaddr_in tmp;
        ::bzero(&tmp, sizeof(tmp));
        socklen_t len = sizeof(tmp);
        int fd = ::accept(_socketfd, (struct sockaddr *)&tmp, &len);
        if (fd < 0)
        {
            return nullptr;
        }

        LOG(LogLevel::DEBUG) << "fd : " << fd;
        InetAddr addr(tmp);
        *client = addr;

        return std::make_shared<TcpSocket>(fd);
    }

    // 关闭
    virtual void Close()
    {
        if (_socketfd < 0)
            return;

        int n = ::close(_socketfd);
        (void)n;
    }

    // 读取
    virtual int Recv(std::string *out)
    {
        char buffer[gsize];
        int n = read(_socketfd, buffer, gsize - 1);
        if (n >0)
        {
            buffer[n] = 0;
            *out = std::string(buffer);
        }
            
        return n;
    }

    // 发送
    virtual int Send(const std::string &in)
    {
        LOG(LogLevel::ERROR) << "准备发送： "<<_socketfd;
        int n = send(_socketfd, in.c_str(), in.size(), 0);
    
        return n;
    }
    virtual int Fd()
    {
        return _socketfd;
    }

private:
    int _socketfd;
};